#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
#include "../../../include/callback_currying/portability/stdint.h"
#include "access.h"

int main(void)
{
    //uintptr_t address = 0;
    unsigned char* aligned_storage = 0;
    size_t i = 0;
    unsigned char* storage = 0;
    unsigned char* storage_backup = 0;
    const char* storage_name = 0;

#define BUFFER_SIZE 1212

    unsigned char stack_storage[BUFFER_SIZE]
    = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
        17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32};

#if defined(UNALIGNED_TEST_STACK_STORAGE)
    storage = stack_storage;
    storage_name = "stack";
#elif defined(UNALIGNED_TEST_HEAP_STORAGE)
    storage = (unsigned char*)malloc(BUFFER_SIZE);
    memcpy(storage,stack_storage,BUFFER_SIZE);
    storage_name = "heap";
#elif defined(UNALIGNED_TEST_FREESTORE_STORAGE)
    storage = new unsigned char[BUFFER_SIZE];
    memcpy(storage,stack_storage,BUFFER_SIZE);
    storage_name = "free store";
#else
#error unknown storage
#endif

#undef BUFFER_SIZE


#ifndef __cplusplus
    printf("-------- C unaligned test --------\n");
#else
    printf("-------- C++ unaligned test --------\n");
#endif

    printf("storage=\"%s\"\n",storage_name);
    printf("\nsizeof(int)=%u\n",(unsigned)sizeof(int));
    /* missing format string in C99 inttypes.h */
    printf("sizeof(uintptr_t)=%u\n\n",(unsigned)sizeof(uintptr_t));

    assert(sizeof(int)!=0);
    i = (uintptr_t)storage % sizeof(int);
    printf("storage=%p, aligned=%s\n"
        ,(void*)storage
        ,i==0?"yes":"no" );

    storage_backup = storage;
    for (;i!=0 && i<=sizeof(int);++i) ++storage;
    aligned_storage = storage;
    printf("first aligned address=%p\n",(void*)aligned_storage);
    
#if defined(UNALIGNED_TEST_READ)
    printf("\n-------- read test --------\n");
    for (i=0;i!=sizeof(int);++i,++storage)
    {
        int unaligned_data = 0;
        size_t j = 0;
        printf("read address=%p,remainder=%d : "
            ,(void*)storage,(int)i);
        unaligned_data = read_int(storage);
        printf(" %0*X,",(unsigned)sizeof(int)*2,(unsigned) unaligned_data);
        for (j=0;j!=sizeof(int);++j)
            printf("%02X ",(unsigned)storage[j]);
        printf("\n");
    }
    printf("-------- read test end --------\n\n");
#endif
#if defined(UNALIGNED_TEST_WRITE)
    printf("\n-------- write test --------\n");
    srand( (unsigned) time(0) );
    for (i=0,storage=aligned_storage;i!=sizeof(int);++i,++storage)
    {
        int random = rand();
        size_t j = 0;
        printf("write address=%p,remainder=%d : "
            ,(void*)storage,(int)i);
        printf(" %0*X,",(unsigned)sizeof(int)*2,(unsigned)random);
        write_int(storage,(size_t)-1/* buffer must be large enough */,random);
        for (j=0;j!=sizeof(int);++j)
            printf("%02X ",(unsigned)storage[j]);
        printf("\n");
    }
    printf("-------- write test end --------\n\n");
#endif

    printf("test succeeded\n");
#ifdef UNALIGNED_TEST_ACCESS_UNALIGNED
    printf("CPU or OS silently corrects any data misalignment accesses\n");
#endif

#if defined(UNALIGNED_TEST_STACK_STORAGE)
#elif defined(UNALIGNED_TEST_HEAP_STORAGE)
    free(storage_backup);
#elif defined(UNALIGNED_TEST_FREESTORE_STORAGE)
    delete [] storage_backup;
#else
#error unknown storage
#endif

    (void)getchar();
    return 0;
}

#include "access.inl"
